001 /*
002 * Copyright 2004 Niclas Hedhman
003 * Copyright 2004-2006 Stephen J. McConnell
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
014 * implied.
015 *
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020 package net.dpml.transit.artifact;
021
022 import java.io.InputStream;
023 import java.io.IOException;
024 import java.io.OutputStream;
025 import java.io.File;
026 import java.net.UnknownServiceException;
027 import java.net.URI;
028 import java.net.URL;
029 import java.net.URLConnection;
030 import java.net.URISyntaxException;
031
032 import net.dpml.transit.Artifact;
033 import net.dpml.transit.Transit;
034 import net.dpml.transit.SecuredTransitContext;
035 import net.dpml.transit.CacheHandler;
036
037 import net.dpml.lang.Part;
038
039 import net.dpml.util.MimeTypeHandler;
040
041 /**
042 * The connection handler for URLs based on the "artifact" protocol family.
043 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
044 * @version 1.0.1
045 */
046 public class ArtifactURLConnection extends URLConnection
047 {
048 // ------------------------------------------------------------------------
049 // state
050 // ------------------------------------------------------------------------
051
052 /**
053 * Transit context.
054 */
055 private final SecuredTransitContext m_context;
056
057 /**
058 * Artifact.
059 */
060 private final Artifact m_artifact;
061
062 /**
063 * Reference fragment.
064 */
065 private final String m_reference;
066
067 /**
068 * The connected state.
069 */
070 private boolean m_connected;
071
072 // ------------------------------------------------------------------------
073 // constructor
074 // ------------------------------------------------------------------------
075
076 /**
077 * Creation of a new handler.
078 * @param url the url to establish a connection with
079 * @param context the transit context
080 * @exception NullPointerException if the url argument is null
081 * @exception IOException if the url argument is invalid
082 */
083 ArtifactURLConnection( URL url, SecuredTransitContext context )
084 throws NullPointerException, IOException
085 {
086 super( url );
087
088 Transit.getInstance(); // make sure Transit is initialized
089
090 m_context = context;
091 m_reference = getReference( url );
092
093 String spec = getRealSpec( url, m_reference );
094 try
095 {
096 m_artifact = Artifact.createArtifact( spec );
097 }
098 catch( URISyntaxException e )
099 {
100 throw new IOException( e.toString() );
101 }
102 }
103
104 // ------------------------------------------------------------------------
105 // URLConnection
106 // ------------------------------------------------------------------------
107
108 /**
109 * Establish a connection. The implementation will attempt to
110 * resolve the resource relative to the cache and associated hosts.
111 *
112 * @exception IOException is an error occurs while attempting to establish
113 * the connection.
114 */
115 public void connect()
116 throws IOException
117 {
118 m_connected = true;
119 }
120
121 /**
122 * Return an input stream to the resource.
123 * @return the input stream
124 * @exception IOException is an error occurs
125 */
126 public InputStream getInputStream()
127 throws IOException
128 {
129 connect();
130 CacheHandler cache = m_context.getCacheHandler();
131 if( null != m_reference )
132 {
133 return cache.getResource( m_artifact, m_reference );
134 }
135 else
136 {
137 return cache.getResource( m_artifact );
138 }
139 }
140
141 /**
142 * Return an output stream to the resource.
143 * @return the output stream
144 * @exception IOException if any I/O problems occur.
145 */
146 public OutputStream getOutputStream()
147 throws IOException
148 {
149 CacheHandler cache = m_context.getCacheHandler();
150 return cache.createOutputStream( m_artifact );
151 }
152
153 /**
154 * Reutrn the mimetype of the content.
155 * @return the content mimetype
156 */
157 public String getContentType()
158 {
159 String type = m_artifact.getType();
160 return MimeTypeHandler.getMimeType( type );
161 }
162
163 /**
164 * Return the content for this artifact.
165 * @return the content object (possibly null)
166 * @exception IOException is an error occurs
167 */
168 public Object getContent()
169 throws IOException
170 {
171 Object content = getContent( new Class[0] );
172 if( content != null )
173 {
174 return content;
175 }
176 else
177 {
178 return super.getContent();
179 }
180 }
181
182 /**
183 * Return the content for this artifact.
184 * @param classes a sequence of classes against which the
185 * implementation will attempt to establish a known match
186 * @return the content object (possibly null)
187 * @exception IOException is an error occurs
188 */
189 public Object getContent( Class[] classes )
190 throws IOException
191 {
192
193 //
194 // attempt to resolve this locally as we may be dealing
195 // with Depot references to the artifact File
196 //
197
198 for( int i=0; i < classes.length; i++ )
199 {
200 Class c = classes[i];
201 if( c.equals( File.class ) )
202 {
203 return m_context.getCacheHandler().getLocalFile( m_artifact );
204 }
205 }
206
207 String type = m_artifact.getType();
208
209 //
210 // if the type is a plugin then handle this directly
211 //
212
213 if( "part".equals( type ) )
214 {
215 URI uri = m_artifact.toURI();
216 Part part = Part.load( uri );
217 return part.getContent( classes );
218 }
219
220 //
221 // otherwise fallback on the default jvm content handling
222 //
223
224 try
225 {
226 Object content = super.getContent( classes );
227 if( content != null )
228 {
229 return content;
230 }
231 }
232 catch( UnknownServiceException use )
233 {
234 boolean ignoreThis = true;
235 }
236
237 return null;
238 }
239
240 // ------------------------------------------------------------------------
241 // implementation
242 // ------------------------------------------------------------------------
243
244 /**
245 * Return a fragment referencing content within the resource referenced by
246 * the artifact.
247 * @param url the url
248 * @return the fragment or null if this is not a referential url
249 */
250 private String getReference( URL url )
251 {
252 String path = url.getPath();
253 int i = path.indexOf( '!' );
254 if( i < 0 )
255 {
256 return null;
257 }
258 else
259 {
260 return path.substring( i );
261 }
262 }
263
264 /**
265 * Return the real specification of the supplied url.
266 * @param url the url to evaluate
267 * @param ref a reference fragment
268 * @return the artifact url spec withough the ref fragment
269 */
270 private String getRealSpec( URL url, String ref )
271 {
272 if( null != ref )
273 {
274 String spec = url.toString();
275 int j = spec.indexOf( ref );
276 if( j > 0 )
277 {
278 String s = spec.substring( 0, j );
279 String version = url.getUserInfo();
280 if( null != version )
281 {
282 s = s + "#" + version;
283 }
284 return s;
285 }
286 }
287 return url.toString();
288 }
289 }